package com.jml.代理模式.五期.手写jdk动态代理.service;

import com.jml.代理模式.五期.手写jdk动态代理.proxy.JavaClassLoader;
import com.jml.代理模式.五期.手写jdk动态代理.proxy.MyExtJdkInvocationHandler;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;



public class MyProxy {
    static String rt = "\r\t";

    //创建代理类
    public static Object newProxyInstance(JavaClassLoader javaClassLoader,
                                          Class<?> classInfo,//接口字节码
                                          MyExtJdkInvocationHandler h) {
        //1.拼接代理类的源代码
        try {
            // 1.创建代理类java源码文件,写入到硬盘中..
            Method[] methods = classInfo.getMethods();//得到接口中的所有方法

            //生成代理java类。
            String proxyClass = "package com.jml.代理模式.五期.手写jdk动态代理.proxy;" + rt
                    + "import java.lang.reflect.Method;" + rt
                    + "import com.jml.代理模式.五期.手写jdk动态代理.proxy.MyExtJdkInvocationHandler;" + rt
                    + "public class $Proxy0 implements  " + classInfo.getName() + "{" + rt
                    + "MyExtJdkInvocationHandler h;" + rt
                    + "public $Proxy0(MyExtJdkInvocationHandler h)" + "{" + rt
                    + "this.h= h;" + rt + "}"
                    + getMethodString(methods, classInfo) + rt + "}";
            System.out.println(proxyClass);


            // 2. 生成的java文件写入到到本地文件中..
            String filename ="D:/code/$Proxy0.java";
            File f = new File(filename);
            FileWriter fw = new FileWriter(f);
            fw.write(proxyClass);
            fw.flush();
            fw.close();
            // 3. 将源代码java文件编译成class文件
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
            Iterable units = fileMgr.getJavaFileObjects(filename);
            JavaCompiler.CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);
            t.call();
            fileMgr.close();
            // 4.使用classLoader 把class加载到内存中..
            Class<?> $Proxy0 = javaClassLoader.findClass("$Proxy0");
            // 5.指明初始化有参数构造函数
            Constructor<?> constructor = $Proxy0.getConstructor(MyExtJdkInvocationHandler.class);
            Object o = constructor.newInstance(h);
            return o;

        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    //接口中的所有方法，接口字节码
    public static String getMethodString(Method[] methods, Class intf) {
        String proxyMe = "";
        for (Method method : methods) {
            proxyMe += "public void " + method.getName() + "() throws Throwable {" + rt
                    + "Method md= " + intf.getName() + ".class.getMethod(\"" + method.getName()
                    + "\",new Class[]{});" + rt
                    + "this.h.invoke(this,md,null);" + rt + "}" + rt;

        }
        return proxyMe;
    }

    public static void main(String[] args) {
        newProxyInstance(new JavaClassLoader(), OrderService.class, null);
    }

}
